/**
 * FIFS - The Find It File System
 * Copyright (C) 2006 Chris Oklota (chris at oklota dot net)
 * 
 * This program is distributed under the terms of the GNU LGPL.
 * See the file http://www.gnu.org/licenses/lgpl.txt
 */
package fifs;

import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;

import fifs.plugin.FifsPlugin;

/**
 * This class contains several utility methods that are handy when dealing
 * with FIFS paths
 */
public class FifsUtils {

    /** The logger for this class */
    public static final Logger log = Logger.getLogger(FifsUtils.class);

    /**
     * Return the set of tags listed in the given path.
     * @param path An absolute FIFS path, in the form:
     *        /tag1/tag2/filename:fh
     * @return The set of tags
     * 
     * TODO - remove search queries from path
     */
    public static Set<String> parseTags(String path) {
        
        HashSet<String> tags = new HashSet<String>();
        
        if (path == null) {
            return tags;
        }
        
        path = path.trim();
        if (path.length() == 0) {
        	return tags;
        }
        
        if (path.charAt(0) != '/') {
        	path = '/' + path;
        }
        
        // all words up to the last '/' are tags
        String[] slashedWords = path.split("/");
        if (slashedWords.length == 0) {
        	return tags;
        }
        for (int i = 1; i < slashedWords.length-1; i++) {
            tags.add(slashedWords[i]);
        }
        
        return tags;
    }
    
    /**
     * Return the filename in the given path, if it exists
     * @param path An absolute FIFS path in the form
     *        /tag1/tag2/filename:fh
     * @return The filename, or null
     */
    public static String parseFilename(String path) {
        
    	if (path == null) {
            return null;
        }
        
        path = path.trim();
        if (path.length() == 0) {
        	return null;
        }
        
        if (path.charAt(0) != '/') {
        	path = '/' + path;
        }
        
        // The filename is everything after the last '/' and
        //  before the first ':', if it exists
        int lastSlash = path.lastIndexOf('/');
        if ((lastSlash == -1) || (lastSlash == path.length()-1)) {
            return null;
        }
        
        int firstColon = path.indexOf(':');
        if (firstColon == -1) {
            firstColon = path.length();
        }
        
        if (firstColon == lastSlash+1) {
        	return null;
        }
        return path.substring(lastSlash+1, firstColon);
    }
    
    /**
     * Return the filename in the given path, if it exists
     * @param path An absolute FIFS path in the form
     *        /tag1/tag2/filename:fh
     * @return The file handle, or -1
     */
    public static long parseFileHandle(String path) {
        
        if (path == null) {
            return -1;
        }
        
        path = path.trim();
        if (path.length() == 0) {
            return -1;
        }
        
        if (path.charAt(0) != '/') {
            path = '/' + path;
        }
        
        // The file handle is everything after the last colon after the last
        // slash, if it exists
        int lastSlash = path.lastIndexOf('/');
        if ((lastSlash == -1) || (lastSlash == path.length()-1)) {
            return -1;
        }
        int lastColon = path.lastIndexOf(':');
        if ((lastColon == -1) || (lastColon < lastSlash)) {
            return -1;
        }
        
        try {
            String fhStr = path.substring(lastColon+1, path.length());
            return Long.parseLong(fhStr);
        } catch (Exception e) {
            return -1;
        }
    }
    
    /**
     * Parse all tokens separated by '/' as tags
     * @param path The input path string to parse
     * @return All tokens separated by '/' in the path
     * 
     * TODO - remove search queries from path
     */
    public static Set<String> parseDirTags(String path) {
    	
    	HashSet<String> tags = new HashSet<String>();
        
        if (path == null) {
            return tags;
        }
        
        path = path.trim();
        if (path.length() == 0) {
        	return tags;
        }
        
        if (path.charAt(0) != '/') {
        	path = '/' + path;
        }
        
        // all words up to the last '/' are tags
        String[] slashedWords = path.split("/");
        if (slashedWords.length == 0) {
        	return tags;
        }
        for (int i = 1; i < slashedWords.length; i++) {
            tags.add(slashedWords[i]);
        }
        
        return tags;
    }
    
    /**
     * Return the set of implicit tags for the given filename based on configuration
     * @param p The properties object holding the config
     * @param filename The filename to get implicit tags for
     * @return The set of tags, which is possibly empty
     */
    public static Set<String> getImplicitTags(Properties p, String filename) {
        HashSet<String> tags = new HashSet<String>();
        int index = filename.lastIndexOf('.');
        if (index != -1) {
            String extension = filename.substring(index+1, filename.length());
            String tagList = p.getProperty("fifs.tags.extension." + extension);
            if (tagList != null) {
                String[] implTags = tagList.split(",");
                for (String s : implTags) {
                    if ((s != null) && (s.length() > 0)) {
                        tags.add(s);
                    }
                }
            }
        }
        return tags;
    }
    
    /**
     * Run the configured plugin, if any, for the given file to add additional tags
     * @param file The file to tag
     * @param path The absolute path to the file
     * @return true if a plugin was run, false otherwise
     */
    public static void runPlugin(Fifs fifs, FifsFile file, String path) {
        
        // get the filename from the path
        String filename = FifsUtils.parseFilename(path);
        int index = filename.lastIndexOf('.');
        if (index != -1) {
            String extension = filename.substring(index+1, filename.length());
            String pluginClass = fifs.getProperties().getProperty("fifs.plugin.extension." + extension);
            if (pluginClass == null) {
                return;
            }
            try {
                Class clazz = Class.forName(pluginClass);
                FifsPlugin plugin = (FifsPlugin)clazz.newInstance();
                plugin.setFile(file);
                plugin.setFilesystem(fifs);
                plugin.setFilePath(path);
                Thread t = new Thread(plugin);
                t.start();
            } catch (Exception e) {
                log.error("Error loading configured plugin class " + pluginClass + " for extension " + extension, e);
            }
        }
    }
}
